#include "irenderer.h"
#include "rendercontext.h"
#include "geometry.h"
#include "ishader.h"
#include "debugdraw.h"
#include "ieffect.h"
#include "effect_basic.h"

namespace gecko
{

void IRenderer::AddBatchedGeometry( GeometryInstance* geometryInstance )
{
	if ( geometryInstance->m_Geometry->m_batch )
	{
		geometryInstance->m_Geometry->m_batch->InstanceList[geometryInstance->m_Geometry->m_primitiveType].PushBack(*geometryInstance);
	}
	else
	{
		GeometryBatch geometryBatch;
		geometryBatch.RenderContext.SetEffect(geometryInstance->m_Geometry->GetEffect());

		GeometryBatchList::Iterator itr = m_GeometryBatchList.Find(geometryBatch);
		if ( itr != m_GeometryBatchList.End() )
		{
			(*itr).InstanceList[geometryInstance->m_Geometry->m_primitiveType].PushBack(*geometryInstance);
			geometryInstance->m_Geometry->m_batch = &(*itr);
		}
		else
		{
			m_GeometryBatchList.PushBack(geometryBatch);
			GeometryBatch* newBatch = &m_GeometryBatchList.Back();
			newBatch->InstanceList[geometryInstance->m_Geometry->m_primitiveType].PushBack(*geometryInstance);
			geometryInstance->m_Geometry->m_batch = newBatch;
		}
	}
}

void IRenderer::RenderBatchedGeometry()
{
	for ( GeometryBatchList::Iterator batchListItr = m_GeometryBatchList.Begin(); batchListItr != m_GeometryBatchList.End(); ++batchListItr )
	{
		GeometryBatch& geometryBatch = (*batchListItr);

		for ( int primitiveType = 0; primitiveType < IVertexBuffer::PT_NUM; primitiveType++ )
		{
			GeometryInstanceList& instanceList = geometryBatch.InstanceList[primitiveType];

			if ( !instanceList.Empty() )
			{
				geometryBatch.RenderContext.SetViewProjectionMatrix(m_viewMatrix * m_projectionMatrix);
				geometryBatch.RenderContext.Begin();

				for ( unsigned int p = 0; p < geometryBatch.RenderContext.GetNumPasses(); p++ )
				{
					geometryBatch.RenderContext.BeginPass(p);

					m_VertexBatcher.Begin((IVertexBuffer::ePrimitiveType)primitiveType);

					for ( GeometryInstanceList::Iterator instanceListIter = instanceList.Begin(); instanceListIter != instanceList.End(); ++instanceListIter )
					{
						GeometryInstance& instance = (*instanceListIter);
						//effect->SetupFromGeometryInstance(instance);
						m_VertexBatcher.AddGeometry(instance);
					}

					m_VertexBatcher.End();

					geometryBatch.RenderContext.EndPass();
				}
				
				geometryBatch.RenderContext.End();

				instanceList.Clear();
			}
		}
	}
}

void IRenderer::RenderDebugLines(IEffect* effect)
{
	effect->Begin();
	effect->BeginPass(0);

	m_VertexBatcher.Begin(IVertexBuffer::PT_LINELIST);

	for ( unsigned int i = 0; i < DebugDrawManager::Get().GetNumDrawers(); i++ )
	{
		DebugDraw* drawer = DebugDrawManager::Get().GetDrawer(i);
		if ( drawer->NeedsRendering() )
		{
			DebugDraw::DebugLineBuffer lineBuffer;
			drawer->Lock(lineBuffer);

			for ( DebugDraw::DebugLineBuffer::Iterator itr = lineBuffer.Begin(); itr != lineBuffer.End(); ++itr )
			{
				//FSAssert(lineBuffer.Size() == 1, "Should only be one line in here");
				Vertex start;
				Vertex end;

				start.Position = (*itr).Start;
				start.Colour = (*itr).StartColour.ToInt();

				end.Position = (*itr).End;
				end.Colour = (*itr).EndColour.ToInt();

				m_VertexBatcher.AddVertex(start);
				m_VertexBatcher.AddVertex(end);
			}

			drawer->Unlock();
		}
	}

	m_VertexBatcher.End();

	effect->EndPass();
	effect->End();
}

}